/*
  Copyright (c) 2014 Dimitrij Gester

  "Smart RC TX" is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  "Smart RC TX" is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with "Smart RC TX"; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/


#ifndef CONFIGURATIONHANDLER_H_
#define CONFIGURATIONHANDLER_H_

#include "CRC.h"

#define VERBOSE_REPLY 0

#ifdef WIN32
#define VERBOSE_REPLY 1
#endif

class ConfigurationCommandReceiver
{
	public:
	virtual void setTrim(uint8_t &channel, int16_t &valueU) = 0;
	virtual void setPreScaler(uint8_t &channel, int16_t &valueU) = 0;
	virtual void setExpo( uint8_t& channel, int16_t &valueU) = 0;
	//virtual void setScaler(uint8_t &channel, int16_t &valueU) = 0;
	virtual void setCrossMixer(uint8_t &source, uint8_t &channel, int16_t &valueU, int16_t &valueD) = 0;
	virtual void setLimiter(uint8_t &channel, int16_t &valueU, int16_t &valueD) = 0;
	//virtual void setATV(uint8_t &channel, int16_t &valueU, int16_t &valueD) = 0;
	virtual void resetMixers() = 0;
	virtual void dumpCurrentConfig() = 0;
	virtual void saveConfig() = 0;
	virtual void loadConfig() = 0;
	
};

class ConfigurationHandler
{
	public:
	ConfigurationHandler(Stream &is, ConfigurationCommandReceiver& cr)
	: inputStream(is)
	, commandReceiver(cr)
	{
	}
	
	public:
	void handleConfiguration()
	{
		static int16_t valueU, valueD;
		static uint8_t source, valBuf;
		static uint8_t crc;
		static uint8_t actualCrc = 0;
		
		while(inputStream.available())
		{
			// reset: 11111111
			// scaleH: 01_Nssss
			// scaleL: 10ssssss
			// enter: 00fnNchN
			uint8_t c = inputStream.read();
			uint8_t cmd = (c >> 6) & 0x03;
			uint8_t data = c & 0x3F;
			uint16_t dataH = (c & 0x0f) << 6;
			uint8_t dataMux = (c >> 4) & 0x01;
			uint8_t crcSelector = (c >> 4) & 0x03;
			uint8_t crcNibble = (c) & 0x0f;
			
			uint8_t function = (c >> 3)	 & 0x07;
			uint8_t channel = (c & 0x07);
			
			if(cmd != 0x03)
				actualCrc = crc8_update(actualCrc, c);
			else
				actualCrc = 0;

			switch(cmd)
			{
				case 0x00: // enter
				if(function != 4)
					{
					if(actualCrc != crc)
					{
						inputStream.print("ERR\n");
					}
					else
					{
						inputStream.print("ACK\n");
					}
					actualCrc = 0;
				}

				switch(function)
				{
					case 0: //trim
					commandReceiver.setTrim(channel, valueU);
					break;
					case 1: //preScale
					commandReceiver.setPreScaler(channel, valueU);
					break;
					case 2: //expo
					commandReceiver.setExpo(channel, valueU);
					break;
					case 3: //scale
					break;
					case 4: //cross-mixer, part 1
					source = channel;
					break;
					case 5: //cross-mixer, part 2
					commandReceiver.setCrossMixer(source, channel, valueU, valueD);
					break;
					case 6: //limiter
					commandReceiver.setLimiter(channel, valueU, valueD);
					break;
					case 7: //atv
					break;
					default:
					break;
				}
				break;
				case 0x01: // scaleH
					if(dataMux)
					{
						valueU = dataH | valBuf;
						valueU -= 512;
					}
					else
					{
						valueD	= dataH | valBuf;
						valueD -= 512;
					}
					break;
				case 0x02: // scaleL
					valBuf = data;
					break;
				case 0x03:
				switch(data)
				{
					case 0x3f:
					valueU = 0;
					valueD = 0;
					source = 0;
					commandReceiver.resetMixers();
					inputStream.print("ACK\n");
					break;
					case 0x00:
					commandReceiver.dumpCurrentConfig();
					inputStream.print("ACK\n");
					break;
					case 0x01:
					commandReceiver.saveConfig();
					inputStream.print("ACK\n");
					break;
					case 0x02:
					commandReceiver.loadConfig();
					inputStream.print("ACK\n");
					break;
					default:
						switch(crcSelector) // 238
						{
						case 1:
							crc &= 0xf0;
							crc |= crcNibble; // 222
							break;
						case 2:
							crc &= 0x0f;
							crc |= crcNibble << 4; //238
							break;
						default:
							break;

						}
					break;
				}
				
				
				break;

				default:
				break;
			}
		}
	}
	private:
	Stream &inputStream;
	ConfigurationCommandReceiver& commandReceiver;
};


#endif /* CONFIGURATIONHANDLER_H_ */